/**************************************************************************************
*
*	Copyright (C) 2010 - 2012 Brent Andrew O. Chua - See LICENSE.txt for more info.
*		
*	Filename	-	RasterizerState.cpp
*
*	Comments	-	See RasterizerState.h
*
**************************************************************************************/
#include "../Include/RasterizerState.h"
#include "../Include/Engine.h"
#include "../Include/GraphicsDevice.h"
#include "../Include/AsyncLoadResource.h"
#include "../Include/XMLParser.h"
#include "../Include/GraphicsTypesMapping.h"

namespace Pulse
{
	RasterizerStateDesc::RasterizerStateDesc( void )
	{
		SetDefault();
	}

	void RasterizerStateDesc::SetDefault( void )
	{
		m_filename.Clear();

		fillMode				= EFillMode::SOLID;
		cullMode				= ECullMode::BACK;
		frontCounterClockwise	= FALSE;
		depthBias				= 0;
		depthBiasClamp			= 0.0f;
		slopeScaledDepthBias	= 0.0f;
		depthClipEnable			= TRUE;
		scissorEnable			= FALSE;
		multisampleEnable		= FALSE;
		antialiasedLineEnable	= FALSE;
	}

	void RasterizerStateDesc::SetToLoad( const CHAR *pFilename )
	{
		m_filename = pFilename;
	}

	RasterizerState::RasterizerState( void )
		: m_pRasterizerState(PSX_NULL)
	{
	}

	RasterizerState::~RasterizerState( void )
	{

	}


	BOOL RasterizerState::CreateResource( BaseResDesc *pDesc )	
	{
		if ( pDesc->GetType() != GetType() )
			return FALSE;

		m_desc = *((RasterizerStateDesc*)pDesc);

		if ( PerformInitialize( m_desc.IsAsyncLoad() ) == EErrorCode::OKAY )
			SetFlagCreated();

		return IsCreated();	
	}

	BOOL RasterizerState::DestroyResource( void )				
	{
		UnloadResource();
		SetFlagDestroyed();	
		return TRUE;	
	}

	BOOL RasterizerState::LoadResource( void )				
	{ 
		if ( Initialize() == EErrorCode::OKAY )
		{
			SetFlagLoaded();	
			return TRUE;	
		}

		return FALSE;
	}

	BOOL RasterizerState::UnloadResource( void )				
	{
		Cleanup();
		SetFlagUnloaded();
		return FALSE;	
	}

	EErrorCode::Type RasterizerState::Initialize( void )
	{
		ID3D11Device *pDevice = (ID3D11Device*)GraphicsDevice::GetInstance()->GetNakedDevice();

		D3D11_RASTERIZER_DESC desc;

		if ( m_desc.m_filename.IsEmpty() == FALSE )
		{
			XMLDocumentPtr pDoc = XMLParser::Load( (PSX_PATH_RASTERIZER_STATES + m_desc.m_filename).GetBuffer() );

			if ( pDoc.IsNull() )
			{
				PSX_PushError( "Failed to load rasterizer state file." );
				return EErrorCode::FILE;
			}

			XMLElementPtr pElem = pDoc->FindChild( PSX_String("RasterizerState") );

			if ( pElem.IsValid() )
			{
				EErrorCode::Type retCode = ProcessRasterizerState( pElem );

				if (  retCode != EErrorCode::OKAY )
				{
					return retCode;
				}
			}
			else
			{
				return EErrorCode::FILE;
			}
		}

		desc.FillMode				= DX11Mapping::ToDXFillMode( m_desc.fillMode );
		desc.CullMode				= DX11Mapping::ToDXCullMode( m_desc.cullMode );
		desc.FrontCounterClockwise	= m_desc.frontCounterClockwise;
		desc.DepthBias				= m_desc.depthBias;
		desc.DepthBiasClamp			= m_desc.depthBiasClamp;
		desc.SlopeScaledDepthBias	= m_desc.slopeScaledDepthBias;
		desc.DepthClipEnable		= m_desc.depthClipEnable;
		desc.ScissorEnable			= m_desc.scissorEnable;
		desc.MultisampleEnable		= m_desc.multisampleEnable;
		desc.AntialiasedLineEnable	= m_desc.antialiasedLineEnable;

		if ( pDevice->CreateRasterizerState( &desc, &m_pRasterizerState ) != S_OK )
		{
			PSX_PushError( "Failed to create rasterizer state." );
			return EErrorCode::GRAPHICS;
		}

		return EErrorCode::NONE;
	}

	void RasterizerState::Cleanup( void )
	{
		PSX_SafeRelease( m_pRasterizerState );
	}

	EErrorCode::Type RasterizerState::ProcessRasterizerState( XMLElementPtr pElem )
	{
		XMLElementPtr pChild; 

		// FillMode
		{
			pChild = pElem->FindChild( PSX_String("FillMode") );

			if ( pChild.IsNull() )
			{
				PSX_PushError( "No FillMode found." );
				return EErrorCode::INVALID_FORMAT;
			}

			EFillMode::Type fillMode = GraphicsTypesMapping::ToFillMode( pChild->GetValue().GetBuffer() );

			if ( fillMode == EFillMode::_UNUSED_ )
				fillMode = EFillMode::SOLID;

			m_desc.fillMode = fillMode;
		}

		// CullMode
		{
			pChild = pElem->FindChild( PSX_String("CullMode") );

			if ( pChild.IsNull() )
			{
				PSX_PushError( "No CullMode found." );
				return EErrorCode::INVALID_FORMAT;
			}

			ECullMode::Type cullMode = GraphicsTypesMapping::ToCullMode( pChild->GetValue().GetBuffer() );

			if ( cullMode == ECullMode::_UNUSED_ )
				cullMode = ECullMode::BACK;

			m_desc.cullMode = cullMode;
		}

		// FrontCounterClockwise
		{
			pChild = pElem->FindChild( PSX_String("FrontCounterClockwise") );

			if ( pChild.IsNull() )
			{
				PSX_PushError( "No FrontCounterClockwise found." );
				return EErrorCode::INVALID_FORMAT;
			}

			m_desc.frontCounterClockwise = pChild->GetValue().ToBOOL();
		}

		// DepthBias
		{
			pChild = pElem->FindChild( PSX_String("DepthBias") );

			if ( pChild.IsNull() )
			{
				PSX_PushError( "No DepthBias found." );
				return EErrorCode::INVALID_FORMAT;
			}

			m_desc.depthBias = pChild->GetValue().ToINT();
		}

		// DepthBiasClamp
		{
			pChild = pElem->FindChild( PSX_String("DepthBiasClamp") );

			if ( pChild.IsNull() )
			{
				PSX_PushError( "No DepthBiasClamp found." );
				return EErrorCode::INVALID_FORMAT;
			}

			m_desc.depthBiasClamp = pChild->GetValue().ToFLOAT();
		}

		// SlopeScaledDepthBias
		{
			pChild = pElem->FindChild( PSX_String("SlopeScaledDepthBias") );

			if ( pChild.IsNull() )
			{
				PSX_PushError( "No SlopeScaledDepthBias found." );
				return EErrorCode::INVALID_FORMAT;
			}

			m_desc.slopeScaledDepthBias = pChild->GetValue().ToFLOAT();
		}

		// DepthClipEnable
		{
			pChild = pElem->FindChild( PSX_String("DepthClipEnable") );

			if ( pChild.IsNull() )
			{
				PSX_PushError( "No DepthClipEnable found." );
				return EErrorCode::INVALID_FORMAT;
			}

			m_desc.depthClipEnable = pChild->GetValue().ToBOOL();
		}

		// ScissorEnable
		{
			pChild = pElem->FindChild( PSX_String("ScissorEnable") );

			if ( pChild.IsNull() )
			{
				PSX_PushError( "No ScissorEnable found." );
				return EErrorCode::INVALID_FORMAT;
			}

			m_desc.scissorEnable = pChild->GetValue().ToBOOL();
		}

		// MultisampleEnable
		{
			pChild = pElem->FindChild( PSX_String("MultisampleEnable") );

			if ( pChild.IsNull() )
			{
				PSX_PushError( "No MultisampleEnable found." );
				return EErrorCode::INVALID_FORMAT;
			}

			m_desc.multisampleEnable = pChild->GetValue().ToBOOL();
		}

		// AntialiasedLineEnable
		{
			pChild = pElem->FindChild( PSX_String("AntialiasedLineEnable") );

			if ( pChild.IsNull() )
			{
				PSX_PushError( "No AntialiasedLineEnable found." );
				return EErrorCode::INVALID_FORMAT;
			}

			m_desc.antialiasedLineEnable = pChild->GetValue().ToBOOL();
		}

		return EErrorCode::OKAY;
	}

}